package com.my.cd.interpret;

import java.util.*;

/**
 * 逆波兰算法分析算式语法
 * 逆波兰表达式也叫后缀表达式，转换后的表达式易于计算机处理
 * eg: input  a+b*(c-d)
 */
public class RPN {

    // a+b*(c-d)
    private List<String> expression = new ArrayList<>();// 存储中缀表达式

    // abcd-*+
    private List<String> right = new ArrayList<>();// 存储后缀表达式

    private AbstractExpression result;// 结果

    // 依据输入信息创建对象，将数值与操作符放入ArrayList中
    public RPN(String input) {
        StringTokenizer st = new StringTokenizer(input, "+-*/()", true);
        while (st.hasMoreElements()) {
            expression.add(st.nextToken());
        }
    }

    // 将中缀表达式转换为后缀表达式
    private void toRight() {
        Stacks stack = new Stacks();
        String operator;
        int position = 0;
        do {
            String tag = expression.get(position);
            if (Helper.isOperator(tag)) {
                if (stack.top == -1 || tag.equals("(")) {
                    stack.push(tag);
                } else {
                    if (tag.equals(")")) {
                        if (!stack.top().equals("(")) {
                            operator = (String) stack.pop();
                            right.add(operator);
                        }
                    } else {
                        if (Helper.priority(tag) <= Helper.priority((String) stack.top()) && stack.top != -1) {
                            operator = (String) stack.pop();
                            if (!operator.equals("("))
                                right.add(operator);
                        }
                        stack.push(tag);
                    }
                }
            } else
                right.add(tag);
        } while (++position < expression.size());

        while (stack.top != -1) {
            operator = (String) stack.pop();
            right.add(operator);
        }
    }

    // 对后缀表达式进行求值 abcd-*+
    public void getResult(HashMap<String, Float> var) {
        this.toRight();
        Stack<AbstractExpression> stack = new Stack<>();
        AbstractExpression op1, op2;
        String is;
        Iterator it = right.iterator();

        while (it.hasNext()) {
            is = (String) it.next();
            if (Helper.isOperator(is)) {
                op2 = stack.pop();
                op1 = stack.pop();
                stack.push(Helper.calc(is, op1, op2));
            } else
                stack.push(new VarExpression(is));
        }
        result = stack.pop();
        it = expression.iterator();
        while (it.hasNext()) {
            System.out.print((String) it.next());
        }
        System.out.println(" = " + result.interpreter(var));
    }

    public static class Helper {
        // 判断是否为操作符号
        public static boolean isOperator(String operator) {
            return operator.equals("+") || operator.equals("-")
                    || operator.equals("*") || operator.equals("/")
                    || operator.equals("(") || operator.equals(")");
        }

        // 设置操作符号的优先级别，数值大优先级高
        public static int priority(String operator) {
            switch (operator) {
                case "+":
                case "-":
                case "(":
                    return 1;//前三个都返回1
                case "*":
                case "/":
                    return 2;//乘除返回2
                default:
                    return 0;//其他返回0
            }
        }

        // 做2值之间的计算
        public static AbstractExpression calc(String op, AbstractExpression a, AbstractExpression b) {
            try {
                AbstractExpression result = null;
                switch (op) {
                    case "+":
                        result = new AddExpression(a, b);
                        break;
                    case "-":
                        result = new SubExpression(a, b);
                        break;
                    case "*":
                        result = new MultiExpression(a, b);
                        break;
                    case "/":
                        result = new DivExpression(a, b);
                        break;
                    default:
                        break;
                }
                return result;
            } catch (NumberFormatException e) {
                System.out.println("input has something wrong!");
                return null;
            }
        }
    }

    // 栈类
    public class Stacks {
        int top = -1;
        private LinkedList list = new LinkedList();

        public void push(Object value) {
            top++;
            list.addFirst(value);
        }

        public Object pop() {
            Object temp = list.getFirst();
            top--;
            list.removeFirst();
            return temp;

        }

        public Object top() {
            return list.getFirst();
        }
    }
}
